package encryption;

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.FileReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.math.BigInteger;
import java.security.KeyFactory;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.NoSuchAlgorithmException;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.spec.RSAPrivateKeySpec;
import java.security.spec.RSAPublicKeySpec;
import java.util.Arrays;


import javax.crypto.Cipher;
import javax.sound.sampled.AudioFormat.Encoding;

import sun.misc.BASE64Decoder;
import sun.misc.BASE64Encoder;

import DAL.RSAKeysDA;

import entities.RSAKeys;

import network.ServerConnection;

public class RSA {
	
	PublicKey publicKey;
	
	PrivateKey privateKey;
	
	private void generateKeys()
	{
		try
		{
		KeyPairGenerator kpg = KeyPairGenerator.getInstance("RSA");
		kpg.initialize(2048);
		KeyPair kp = kpg.genKeyPair();
		KeyFactory fact = KeyFactory.getInstance("RSA");
		publicKey=kp.getPublic();
		privateKey=kp.getPrivate();
		RSAPublicKeySpec pub = fact.getKeySpec(publicKey,RSAPublicKeySpec.class);
		RSAPrivateKeySpec priv = fact.getKeySpec(privateKey,RSAPrivateKeySpec.class);
		saveToDatabase(pub.getModulus(),pub.getPublicExponent(),priv.getModulus(),priv.getPrivateExponent());
		}
		catch(Exception e)
		{
			e.printStackTrace();
		}
	}
	
	public void saveToDatabase(BigInteger modPb,BigInteger expPb,BigInteger modPr,BigInteger expPr)
	{
		RSAKeys rsa=new RSAKeys();
		rsa.setPublicKey(modPb.toString()+"-"+expPb.toString());
		rsa.setPrivateKey(modPr.toString()+"-"+expPr.toString());
		
		RSAKeysDA da=new RSAKeysDA();
		da.insertRSAKeys(rsa);
	}
	
	public void setKeysFromDB()
	{
		
		RSAKeys rsa1=new RSAKeys();
		RSAKeysDA da=new RSAKeysDA();
		RSAKeys[] keys=da.selectRSAKeys(rsa1);
		
		if(keys==null||keys.length==0)
		{
			generateKeys();
			return;
		}
		RSAKeys rsa=keys[0];
		String[]pbParam=rsa.getPublicKey().split("-");
		String[]prParam=rsa.getPrivateKey().split("-");
		RSAPublicKeySpec keySpecPb = new RSAPublicKeySpec(new BigInteger(pbParam[0]),new BigInteger(pbParam[1]));
		try
		{
	    KeyFactory fact = KeyFactory.getInstance("RSA");
	     publicKey = fact.generatePublic(keySpecPb);
	     
	     RSAPrivateKeySpec keySpecPr = new RSAPrivateKeySpec(new BigInteger(prParam[0]),new BigInteger(prParam[1]));
		    
		 privateKey= fact.generatePrivate(keySpecPr); 
		
		}
		catch(Exception e)
		{
			e.printStackTrace();
			
		}
		
		
	}
	PublicKey readKeyFromFile(String keyFileName) throws IOException {
		  InputStream in =
		    ServerConnection.class.getResourceAsStream(keyFileName);
		  ObjectInputStream oin =
		    new ObjectInputStream(new BufferedInputStream(in));
		  try {
		    BigInteger m = (BigInteger) oin.readObject();
		    BigInteger e = (BigInteger) oin.readObject();
		    RSAPublicKeySpec keySpec = new RSAPublicKeySpec(m, e);
		    KeyFactory fact = KeyFactory.getInstance("RSA");
		    PublicKey pubKey = fact.generatePublic(keySpec);
		    return pubKey;
		  } catch (Exception e) {
		    throw new RuntimeException("Spurious serialisation error", e);
		  } finally {
		    oin.close();
		  }
		}
	PrivateKey readKeyFromFileP(String keyFileName) throws IOException {
		  InputStream in =
		    ServerConnection.class.getResourceAsStream(keyFileName);
		  ObjectInputStream oin =
		    new ObjectInputStream(new BufferedInputStream(in));
		  try {
		    BigInteger m = (BigInteger) oin.readObject();
		    BigInteger e = (BigInteger) oin.readObject();
		    RSAPrivateKeySpec keySpec = new RSAPrivateKeySpec(m, e);
		    KeyFactory fact = KeyFactory.getInstance("RSA");
		    PrivateKey pubKey = fact.generatePrivate(keySpec);
		    return pubKey;
		  } catch (Exception e) {
		    throw new RuntimeException("Spurious serialisation error", e);
		  } finally {
		    oin.close();
		  }
		}
	
	public String rsaEncrypt(String msg)  {
		try
		{
		 
		  setKeysFromDB();
		  return rsaEncrypt(msg,publicKey);
		}
		catch(Exception e)
		{
			e.printStackTrace();
		}
		return null;
		}
	
	public String rsaEncrypt(String msg,PublicKey pubKey)
	{
		try
		{
		  byte [] data=base64ToByte(msg);
		 
		  
		  Cipher cipher = Cipher.getInstance("RSA");
		  cipher.init(Cipher.ENCRYPT_MODE, pubKey);
		  byte[] cipherData = cipher.doFinal(data);
		  return byteToBase64(cipherData);
		}
		catch(Exception e)
		{
			e.printStackTrace();
		}
		return null;
	}
	public String rsaEncrypt(String msg,String mod,String exp)
	{
		try
		{
			RSAPublicKeySpec keySpecPb = new RSAPublicKeySpec(new BigInteger(mod),new BigInteger(exp));
			
		    KeyFactory fact = KeyFactory.getInstance("RSA");
		    PublicKey pubKey = fact.generatePublic(keySpecPb);
		     
		  byte [] data=msg.getBytes("ISO-8859-1");
		  System.out.println(data.length);
		  
		  Cipher cipher = Cipher.getInstance("RSA");
		  cipher.init(Cipher.ENCRYPT_MODE, pubKey);
		  byte[] cipherData = cipher.doFinal(data);
		  return new String(cipherData,"ISO-8859-1");
		}
		catch(Exception e)
		{
			e.printStackTrace();
		}
		return null;
	}
	public byte[] rsaEncryptPrivate(String msg,String mod,String exp)
	{
		try
		{
			RSAPrivateKeySpec keySpecPb = new RSAPrivateKeySpec(new BigInteger(mod),new BigInteger(exp));
			
		    KeyFactory fact = KeyFactory.getInstance("RSA");
		    PrivateKey pubKey = fact.generatePrivate(keySpecPb);
		     
		  byte [] data=msg.getBytes("ISO-8859-1");
		  System.out.println(data.length);
		  
		  Cipher cipher = Cipher.getInstance("RSA");
		  cipher.init(Cipher.ENCRYPT_MODE, pubKey);
		  byte[] cipherData = cipher.doFinal(data);
		  return cipherData;
		}
		catch(Exception e)
		{
			e.printStackTrace();
		}
		return null;
	}
	
	public byte[] rsaEncryptToBytes(String msg,String mod,String exp)
	{
		try
		{
			RSAPublicKeySpec keySpecPb = new RSAPublicKeySpec(new BigInteger(mod),new BigInteger(exp));
			
		    KeyFactory fact = KeyFactory.getInstance("RSA");
		    PublicKey pubKey = fact.generatePublic(keySpecPb);
		     
		  byte [] data=msg.getBytes("ISO-8859-1");
		  System.out.println(data.length);
		  
		  Cipher cipher = Cipher.getInstance("RSA");
		  cipher.init(Cipher.ENCRYPT_MODE, pubKey);
		  byte[] cipherData = cipher.doFinal(data);
		  return cipherData;
		}
		catch(Exception e)
		{
			e.printStackTrace();
		}
		return null;
	}
	
	public String rsadecrypt(String msg)  {
		try
		{
		  
		  setKeysFromDB();
		  return rsadecrypt(msg,privateKey);
		}
		catch(Exception e)
		{
			e.printStackTrace();
		}
		return null;
		}
	public String rsadecrypt(String msg,PrivateKey priKey)
	{
		try
		{
			  byte [] data=base64ToByte(msg);
			  
			  Cipher cipher = Cipher.getInstance("RSA");
			  cipher.init(Cipher.DECRYPT_MODE, priKey);
			  byte[] cipherData = cipher.doFinal(data);
			  return byteToBase64(cipherData);
			
		}
		catch(Exception e)
		{
			e.printStackTrace();
			
		}
		return null;
		
	}
	
	public String rsadecrypt(String msg,String mod,String exp)
	{
		try
		{
		  KeyFactory fact = KeyFactory.getInstance("RSA");
	      RSAPrivateKeySpec keySpecPr = new RSAPrivateKeySpec(new BigInteger(mod),new BigInteger(exp));
		    
		  PrivateKey priKey= fact.generatePrivate(keySpecPr);
		  byte [] data=msg.getBytes("ISO-8859-1");
		  Cipher cipher = Cipher.getInstance("RSA");
		  cipher.init(Cipher.DECRYPT_MODE, priKey);
		 
		  byte[] cipherData = cipher.doFinal(data);
		  return new String(cipherData,"ISO-8859-1");
		}
		catch(Exception e)
		{
			e.printStackTrace();
		}
		return null;
		
	}
	public String rsadecryptPublic(String msg,String mod,String exp)
	{
		try
		{
		  KeyFactory fact = KeyFactory.getInstance("RSA");
	      RSAPublicKeySpec keySpecPr = new RSAPublicKeySpec(new BigInteger(mod),new BigInteger(exp));
		    
		  PublicKey priKey= fact.generatePublic(keySpecPr);
		  byte [] data=msg.getBytes("ISO-8859-1");
		  Cipher cipher = Cipher.getInstance("RSA");
		  cipher.init(Cipher.DECRYPT_MODE, priKey);
		 
		  byte[] cipherData = cipher.doFinal(data);
		  return new String(cipherData,"ISO-8859-1");
		}
		catch(Exception e)
		{
			e.printStackTrace();
		}
		return null;
		
	}
	public static String byteToBase64(byte [] bytes){
		BASE64Encoder encoder = new BASE64Encoder();
		return encoder.encode(bytes);
	}
	
	public static byte[] base64ToByte(String data) throws IOException{
		BASE64Decoder decoder = new BASE64Decoder();
		return decoder.decodeBuffer(data);
	}
	
	public static void main(String []args) throws Exception
	{
		RSA rsa=new RSA();

	//	rsa.generateKeys();
		
	
		String s = rsa.rsaEncrypt("sdsfsd" , "20933460749432575217334381777058471331301493740374616705148769499805250963247808290685090402617548284135775594628275659638677185581251302510135025928441179272839574620827721132069021233071821355572378366192461219436764318678652837174798617260920569130559861071080236014771218948146560709489003058133737564710113119690796009796491833075775450813102849152135514564440276664640401918591454988637327897533078188241042687677594249848775767520517131919594651846169535352102651682871981963072682344980077032214435239799418195563595995226474078153014757286078987648908955125278827944385334589478822652160627442975709310329633" , "65537");
		System.out.println(s.length());

		System.out.println(rsa.rsadecrypt( s, "20933460749432575217334381777058471331301493740374616705148769499805250963247808290685090402617548284135775594628275659638677185581251302510135025928441179272839574620827721132069021233071821355572378366192461219436764318678652837174798617260920569130559861071080236014771218948146560709489003058133737564710113119690796009796491833075775450813102849152135514564440276664640401918591454988637327897533078188241042687677594249848775767520517131919594651846169535352102651682871981963072682344980077032214435239799418195563595995226474078153014757286078987648908955125278827944385334589478822652160627442975709310329633" , "3620881502900158271872416372808258403827360621341938980569242581286789522245100550577630724690976507148071351155929213690953882169599840780854946883818441616749460883191220940127476459070481817702496012316061772487833747601220815145849171083049202308070656043178136861062400445491698005748925624715871172521637029435918105522585822533307996418488232941216486704573943546705578345774679089554754867397781298204874096754679579069422260050314154430715038700407333328748191646495057696927472254656081214635750896257992538180755910070777047131546348663781780030623572332244737889835280297494466090995605241656072761386497"));

	}

}
